/**
 * Copyright 2012 Facebook
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.scrumptious;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.facebook.FacebookRequestError;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionDefaultAudience;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.model.GraphObject;
import com.facebook.model.GraphUser;
import com.facebook.model.OpenGraphAction;
import com.facebook.widget.ProfilePictureView;
import com.koushikdutta.urlimageviewhelper.UrlImageViewHelper;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.types.User;

/**
 * Fragment that represents the main selection screen for Scrumptious.
 */
public class SelectionFragment extends Fragment {

	private static final String TAG = "SelectionFragment";
	private static final String PENDING_ANNOUNCE_KEY = "pendingAnnounce";
	private static final Uri M_FACEBOOK_URL = Uri
			.parse("http://m.facebook.com");

	private static final int REAUTH_ACTIVITY_CODE = 100;
	private static final List<String> PERMISSIONS = Arrays.asList(
			"friends_birthday", "friends_events", "friends_likes",
			"friends_groups", "friends_interests", "friends_status",
			"friends_checkins");
	protected static Object PeopleListElement;

	private Button searchButton;
	private ListView listView;
	private List<BaseListElement> listElements;
	private ProfilePictureView profilePictureView;
	private ImageView profileView;
	private TextView userNameView;
	private boolean pendingAnnounce;

	private UiLifecycleHelper uiHelper;
	private Session.StatusCallback callback = new Session.StatusCallback() {
		@Override
		public void call(final Session session, final SessionState state,
				final Exception exception) {
			onSessionStateChange(session, state, exception);
		}
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		uiHelper = new UiLifecycleHelper(getActivity(), callback);
		uiHelper.onCreate(savedInstanceState);

	}

	@Override
	public void onResume() {
		super.onResume();
		uiHelper.onResume();
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		super.onCreateView(inflater, container, savedInstanceState);
		View view = inflater.inflate(R.layout.selection, container, false);

		profilePictureView = (ProfilePictureView) view
				.findViewById(R.id.selection_profile_pic);
		profilePictureView.setCropped(true);
		// profileView = (ImageView)
		// view.findViewById(R.id.selection_profile_pic);
		userNameView = (TextView) view.findViewById(R.id.selection_user_name);

		searchButton = (Button) view.findViewById(R.id.search_button);
		Global.searchButton = searchButton;
		// listView = (ListView) view.findViewById(R.id.selection_list);

		// USTAWIANIE GLOBALI WIDOKOW DLA SORTOWANEJ LISTY ZNAJOMYCH
		TextView friendUserName = (TextView) view
				.findViewById(R.id.friend_user_name);
		Global.friendUserName = friendUserName;
		TextView friendUserBirthday = (TextView) view
				.findViewById(R.id.friend_user_birthday);
		Global.friendUserBirthday = friendUserBirthday;
		TextView friendUserCount = (TextView) view
				.findViewById(R.id.friend_user_count);
		Global.friendUserCount = friendUserCount;
		ProfilePictureView friendUserPic = (ProfilePictureView) view
				.findViewById(R.id.friend_profile_pic);
		Global.friendUserPic = friendUserPic;

		searchButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				srartSearching();
			}
		});
		init(savedInstanceState);

		return view;
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == REAUTH_ACTIVITY_CODE) {
			uiHelper.onActivityResult(requestCode, resultCode, data);
		} else if (resultCode == Activity.RESULT_OK && requestCode >= 0
				&& requestCode < listElements.size()) {
			listElements.get(requestCode).onActivityResult(data);
			searchButton.setEnabled(true);
		}
	}

	@Override
	public void onSaveInstanceState(Bundle bundle) {
		super.onSaveInstanceState(bundle);
		for (BaseListElement listElement : listElements) {
			listElement.onSaveInstanceState(bundle);
		}
		bundle.putBoolean(PENDING_ANNOUNCE_KEY, pendingAnnounce);
		uiHelper.onSaveInstanceState(bundle);
	}

	@Override
	public void onPause() {
		super.onPause();
		uiHelper.onPause();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		uiHelper.onDestroy();
	}

	/**
	 * Notifies that the session token has been updated.
	 */
	private void tokenUpdated() {
		if (pendingAnnounce) {
			srartSearching();
		}
	}

	private void onSessionStateChange(final Session session,
			SessionState state, Exception exception) {
		if (session != null && session.isOpened()) {
			if (state.equals(SessionState.OPENED_TOKEN_UPDATED)) {
				tokenUpdated();
			} else {
				makeMeRequest(session);
			}
		}
	}

	private void makeMeRequest(final Session session) {
		Request request = Request.newMeRequest(session,
				new Request.GraphUserCallback() {
					@Override
					public void onCompleted(GraphUser user, Response response) {
						if (session == Session.getActiveSession()) {
							if (user != null) {
								profilePictureView.setProfileId(user.getId());
								userNameView.setText(user.getName());
							}
						}
						if (response.getError() != null) {
							handleError(response.getError());
						}
					}
				});
		request.executeAsync();

	}

	/**
	 * Resets the view to the initial defaults.
	 */
	private void init(Bundle savedInstanceState) {
		searchButton.setEnabled(false);

		listElements = new ArrayList<BaseListElement>();
		listElements.add(new PeopleListElement(0));

		if (savedInstanceState != null) {
			for (BaseListElement listElement : listElements) {
				listElement.restoreState(savedInstanceState);
			}
			pendingAnnounce = savedInstanceState.getBoolean(
					PENDING_ANNOUNCE_KEY, false);
		}

		// listView.setAdapter(new ActionListAdapter(getActivity(),
		// R.id.selection_list, listElements));

		Session session = Session.getActiveSession();
		if (session != null && session.isOpened()) {
			makeMeRequest(session);
		}
	}

	private void srartSearching() {
		// TODO start searching
	}

	private void requestPublishPermissions(Session session) {
		if (session != null) {
			Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(
					this, PERMISSIONS)
					// demonstrate how to set an audience for the publish
					// permissions,
					// if none are set, this defaults to FRIENDS
					.setDefaultAudience(SessionDefaultAudience.FRIENDS)
					.setRequestCode(REAUTH_ACTIVITY_CODE);
			session.requestNewPublishPermissions(newPermissionsRequest);
		}
	}

	private void handleError(FacebookRequestError error) {
		DialogInterface.OnClickListener listener = null;
		String dialogBody = null;

		if (error == null) {
			dialogBody = getString(R.string.error_dialog_default_text);
		} else {
			switch (error.getCategory()) {
			case AUTHENTICATION_RETRY:
				// tell the user what happened by getting the message id, and
				// retry the operation later
				String userAction = (error.shouldNotifyUser()) ? ""
						: getString(error.getUserActionMessageId());
				dialogBody = getString(R.string.error_authentication_retry,
						userAction);
				listener = new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						Intent intent = new Intent(Intent.ACTION_VIEW,
								M_FACEBOOK_URL);
						startActivity(intent);
					}
				};
				break;

			case AUTHENTICATION_REOPEN_SESSION:
				// close the session and reopen it.
				dialogBody = getString(R.string.error_authentication_reopen);
				listener = new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						Session session = Session.getActiveSession();
						if (session != null && !session.isClosed()) {
							session.closeAndClearTokenInformation();
						}
					}
				};
				break;

			case PERMISSION:
				// request the publish permission
				dialogBody = getString(R.string.error_permission);
				listener = new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						pendingAnnounce = true;
						requestPublishPermissions(Session.getActiveSession());
					}
				};
				break;

			case SERVER:
			case THROTTLING:
				// this is usually temporary, don't clear the fields, and
				// ask the user to try again
				dialogBody = getString(R.string.error_server);
				break;

			case BAD_REQUEST:
				// this is likely a coding error, ask the user to file a bug
				dialogBody = getString(R.string.error_bad_request,
						error.getErrorMessage());
				break;

			case OTHER:
			case CLIENT:
			default:
				// an unknown issue occurred, this could be a code error, or
				// a server side issue, log the issue, and either ask the
				// user to retry, or file a bug
				dialogBody = getString(R.string.error_unknown,
						error.getErrorMessage());
				break;
			}
		}

		new AlertDialog.Builder(getActivity())
				.setPositiveButton(R.string.error_dialog_button_text, listener)
				.setTitle(R.string.error_dialog_title).setMessage(dialogBody)
				.show();
	}

	private void startPickerActivity(Uri data, int requestCode) {
		Intent intent = new Intent();
		intent.setData(data);
		intent.setClass(getActivity(), PickerActivity.class);
		startActivityForResult(intent, requestCode);
	}

	public class PeopleListElement extends BaseListElement {

		private static final String FRIENDS_KEY = "friends";

		private List<GraphUser> selectedUsers;

		public List<GraphUser> getSelectedUsers() {
			return selectedUsers;
		}

		public PeopleListElement(int requestCode) {
			super(getActivity().getResources().getDrawable(
					R.drawable.action_people), "Your friend", getActivity()
					.getResources().getString(R.string.action_people_default),
					requestCode);
		}

		@Override
		protected View.OnClickListener getOnClickListener() {
			return new View.OnClickListener() {
				@Override
				public void onClick(View view) {
					startPickerActivity(PickerActivity.FRIEND_PICKER,
							getRequestCode());
				}
			};
		}

		@Override
		protected void onActivityResult(Intent data) {
			selectedUsers = ((ScrumptiousApplication) getActivity()
					.getApplication()).getSelectedUsers();
			setUsersText();
			notifyDataChanged();
		}

		@Override
		protected void populateOGAction(OpenGraphAction action) {
			if (selectedUsers != null) {
				action.setTags(selectedUsers);
			}
		}

		@Override
		protected void onSaveInstanceState(Bundle bundle) {
			if (selectedUsers != null) {
				bundle.putByteArray(FRIENDS_KEY, getByteArray(selectedUsers));
			}
		}

		@Override
		protected boolean restoreState(Bundle savedState) {
			byte[] bytes = savedState.getByteArray(FRIENDS_KEY);
			if (bytes != null) {
				selectedUsers = restoreByteArray(bytes);
				setUsersText();
				return true;
			}
			return false;
		}

		String getMonthForInt(int m) {
			String month = "invalid";
			DateFormatSymbols dfs = new DateFormatSymbols();
			String[] months = dfs.getMonths();
			if (m >= 0 && m <= 11) {
				month = months[m];
			}
			return month;
		}

		public void setUsersText() {
			String text = null;
			String birthsday = null;
			if (selectedUsers != null) {
				if (selectedUsers.size() == 1) {
					text = String.format(
							getResources().getString(
									R.string.single_user_selected),
							selectedUsers.get(0).getName());
					birthsday = selectedUsers.get(0).getBirthday();
					if (selectedUsers.get(0).getBirthday() != null)
						Log.d("BIRTHSDAY:", selectedUsers.get(0).getBirthday());
					else
						Log.d("BIRTHSDAY:", "none");
					Log.d("JSON:", selectedUsers.get(0).getInnerJSONObject()
							.toString());
					// try {
					// UrlImageViewHelper.setUrlDrawable(profileView,selectedUsers.get(0).getInnerJSONObject().getJSONObject("picture").getJSONObject("data").getString("url"));
					// Log.d("LINK:",selectedUsers.get(0).getInnerJSONObject().getJSONObject("picture").getJSONObject("data").getString("url"));
					// } catch (JSONException e) {
					// // TODO Auto-generated catch block
					// e.printStackTrace();
					// }
				}
			}
			if (text == null) {
				text = getResources().getString(R.string.action_people_default);
			}
			setText1(text);
			if (birthsday == null) {
				String friendId = selectedUsers.get(0).getId();
				birthsday = "";
				try {
					String accessToken = Session.getActiveSession()
							.getAccessToken();
					FacebookClient facebookClient = new DefaultFacebookClient(
							accessToken);
					User user = facebookClient
							.fetchObject(friendId, User.class);
					Calendar cal = Calendar.getInstance();
					cal.setTime(user.getBirthdayAsDate());
					birthsday = "" + cal.get(Calendar.DAY_OF_MONTH) + " "
							+ getMonthForInt(cal.get(Calendar.MONTH)) + " "
							+ cal.get(Calendar.YEAR);
				} catch (Exception e) {
					e.printStackTrace();

				}

			} else
				birthsday = "";
			setText2(birthsday);
		}

		private byte[] getByteArray(List<GraphUser> users) {
			// convert the list of GraphUsers to a list of String where each
			// element is
			// the JSON representation of the GraphUser so it can be stored in a
			// Bundle
			List<String> usersAsString = new ArrayList<String>(users.size());

			for (GraphUser user : users) {
				usersAsString.add(user.getInnerJSONObject().toString());
			}
			try {
				ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
				new ObjectOutputStream(outputStream).writeObject(usersAsString);
				return outputStream.toByteArray();
			} catch (IOException e) {
				Log.e(TAG, "Unable to serialize users.", e);
			}
			return null;
		}

		private List<GraphUser> restoreByteArray(byte[] bytes) {
			try {
				@SuppressWarnings("unchecked")
				List<String> usersAsString = (List<String>) (new ObjectInputStream(
						new ByteArrayInputStream(bytes))).readObject();
				if (usersAsString != null) {
					List<GraphUser> users = new ArrayList<GraphUser>(
							usersAsString.size());
					for (String user : usersAsString) {
						GraphUser graphUser = GraphObject.Factory.create(
								new JSONObject(user), GraphUser.class);
						users.add(graphUser);
					}
					return users;
				}
			} catch (ClassNotFoundException e) {
				Log.e(TAG, "Unable to deserialize users.", e);
			} catch (IOException e) {
				Log.e(TAG, "Unable to deserialize users.", e);
			} catch (JSONException e) {
				Log.e(TAG, "Unable to deserialize users.", e);
			}
			return null;
		}
	}

	private class ActionListAdapter extends ArrayAdapter<BaseListElement> {
		private List<BaseListElement> listElements;

		public ActionListAdapter(Context context, int resourceId,
				List<BaseListElement> listElements) {
			super(context, resourceId, listElements);
			this.listElements = listElements;
			for (int i = 0; i < listElements.size(); i++) {
				listElements.get(i).setAdapter(this);
			}
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view = convertView;
			if (view == null) {
				LayoutInflater inflater = (LayoutInflater) getActivity()
						.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				view = inflater.inflate(R.layout.listitem, null);
			}

			BaseListElement listElement = listElements.get(position);
			if (listElement != null) {
				view.setOnClickListener(listElement.getOnClickListener());
				ImageView icon = (ImageView) view.findViewById(R.id.icon);
				TextView text1 = (TextView) view.findViewById(R.id.text1);
				TextView text2 = (TextView) view.findViewById(R.id.text2);
				if (icon != null) {
					icon.setImageDrawable(listElement.getIcon());
					try {
						UrlImageViewHelper
								.setUrlDrawable(icon,
										((PeopleListElement) (listElements
												.get(position)))
												.getSelectedUsers().get(0)
												.getInnerJSONObject()
												.getJSONObject("picture")
												.getJSONObject("data")
												.getString("url"));
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					// UrlImageViewHelper.setUrlDrawable(profileView,selectedUsers.get(0).getInnerJSONObject().getJSONObject("picture").getJSONObject("data").getString("url"));
				}
				if (text1 != null) {
					text1.setText(listElement.getText1());
				}
				if (text2 != null) {
					text2.setText(listElement.getText2());
				}
			}
			return view;
		}

	}

}
